package com.leyou.service;

import com.leyou.client.UserClient;
import com.leyou.domian.Payload;
import com.leyou.domian.UserInfo;
import com.leyou.exception.LyException;
import com.leyou.exception.domain.ExceptionEnum;
import com.leyou.utils.CookieUtils;
import com.leyou.utils.JwtUtils;
import com.leyou.UserDTO;
import com.leyou.config.JwtProperties;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.PrivateKey;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class AuthService {
    @Autowired
    UserClient client;

    @Autowired
    JwtProperties properties;

    @Autowired
    StringRedisTemplate redisTemplate;

    /**
     * 通过feign接口调用用户服务，然后得到一个token，将token写到cookie中
     *
     * @param username
     * @param password
     */
    public void login(String username, String password,HttpServletRequest request, HttpServletResponse response) {
        UserDTO userDTO = client.findUserNameAndPassword(username, password);
        if (userDTO == null) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        //获取载荷中的对象
        UserInfo userInfo = new UserInfo();
        userInfo.setId(userDTO.getId());
        userInfo.setUsername(userDTO.getUsername());
        addTokenTOCookie(request,userInfo, response);
    }

    /**
     * 将用户信息转成token写到cookie中去
     *
     * @param userInfo
     * @param response
     */
    private void addTokenTOCookie(HttpServletRequest request,UserInfo userInfo, HttpServletResponse response) {
        PrivateKey privateKey = properties.getPrivateKey();
        String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, properties.getUser().getExpire());
        redisTemplate.opsForValue().set(userInfo.getId().toString(), token);
        CookieUtils.newCookieBuilder().response(response).name(properties.getUser().getCookieName()).request(request)
                .domain(properties.getUser().getCookieDomain())
                .value(token).httpOnly(true).build();
    }

    /**
     * 验证登录
     * Token的续签问题,采用方式,每次刷新的时候，判断当前时间和过期时间的一半，如果大于过期时间的一半，就
     * 刷新token
     *
     * @param request
     * @param response
     * @return
     */
    public UserInfo verify(HttpServletRequest request, HttpServletResponse response) {
        //得到token，获得里面的userInfo信息，将信息返回
        String token = CookieUtils.getCookieValue(request, properties.getUser().getCookieName());
        if (token == null) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        if (redisTemplate.opsForValue().get(token) != null) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        Payload<UserInfo> userInfo = JwtUtils.getInfoFromToken(token, properties.getPublicKey(), UserInfo.class);
        if (userInfo == null) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }

        int expire = properties.getUser().getExpire();
        DateTime dateTime = new DateTime(userInfo.getExpiration().getTime()).minusMinutes(expire / 2);

        if (DateTime.now().getMillis() - dateTime.getMillis() > 0) {
            addTokenTOCookie(request,userInfo.getUserInfo(), response);
            log.info("刷新token");
        }
        return userInfo.getUserInfo();
    }

    /**
     * 登出，将token写到redis中，然后删掉cookie
     */
    public void logout(HttpServletRequest request, HttpServletResponse response) {

        String token = CookieUtils.getCookieValue(request, properties.getUser().getCookieName());

        if (token == null) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        Payload<UserInfo> userInfo = JwtUtils.getInfoFromToken(token, properties.getPublicKey(), UserInfo.class);
        if (userInfo == null) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        redisTemplate.opsForValue().set(token, "token", userInfo.getExpiration().getTime(), TimeUnit.MILLISECONDS);
        String cookieName = properties.getUser().getCookieName();
        String domain = properties.getUser().getCookieDomain();
        CookieUtils.deleteCookie(cookieName, domain, response);
    }
}
